//! Error handling module for the Rust GraphQL application
//! 
//! This module provides comprehensive error types and handling for all
//! operations in the GraphQL generator.

use thiserror::Error;

/// Main error type for the application
#[derive(Error, Debug)]
pub enum Error {
    /// Database connection or query errors
    #[error("Database error: {0}")]
    Database(#[from] sea_orm::DbErr),
    
    /// GraphQL schema or execution errors
    #[error("GraphQL error: {0}")]
    GraphQL(String),
    
    /// Configuration errors
    #[error("Configuration error: {0}")]
    Config(String),
    
    /// Type mapping errors
    #[error("Type mapping error: {0}")]
    TypeMapping(String),
    
    /// Validation errors
    #[error("Validation error: {0}")]
    Validation(String),
    
    /// IO errors
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    
    /// Serialization/deserialization errors
    #[error("Serialization error: {0}")]
    Serialization(#[from] serde_json::Error),
    
    /// Generic errors
    #[error("Internal error: {0}")]
    Internal(String),
    
    /// Not found errors
    #[error("Not found: {0}")]
    NotFound(String),
    
    /// Permission denied errors
    #[error("Permission denied: {0}")]
    PermissionDenied(String),
}

/// Result type alias for convenience
pub type Result<T> = std::result::Result<T, Error>;

impl Error {
    /// Create a new GraphQL error
    pub fn graphql<S: Into<String>>(message: S) -> Self {
        Self::GraphQL(message.into())
    }
    
    /// Create a new configuration error
    pub fn config<S: Into<String>>(message: S) -> Self {
        Self::Config(message.into())
    }
    
    /// Create a new type mapping error
    pub fn type_mapping<S: Into<String>>(message: S) -> Self {
        Self::TypeMapping(message.into())
    }
    
    /// Create a new validation error
    pub fn validation<S: Into<String>>(message: S) -> Self {
        Self::Validation(message.into())
    }
    
    /// Create a new internal error
    pub fn internal<S: Into<String>>(message: S) -> Self {
        Self::Internal(message.into())
    }
    
    /// Create a new not found error
    pub fn not_found<S: Into<String>>(message: S) -> Self {
        Self::NotFound(message.into())
    }
    
    /// Create a new permission denied error
    pub fn permission_denied<S: Into<String>>(message: S) -> Self {
        Self::PermissionDenied(message.into())
    }
}

/// Convert anyhow errors to our error type
impl From<anyhow::Error> for Error {
    fn from(err: anyhow::Error) -> Self {
        Self::Internal(err.to_string())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_error_creation() {
        let err = Error::graphql("Test GraphQL error");
        assert!(matches!(err, Error::GraphQL(_)));
        assert_eq!(err.to_string(), "GraphQL error: Test GraphQL error");
    }
    
    #[test]
    fn test_error_conversion_to_graphql() {
        let err = Error::not_found("User not found");
        let graphql_err: async_graphql::Error = err.into();
        assert_eq!(graphql_err.message, "User not found");
    }
    
    #[test]
    fn test_result_type() {
        fn test_function() -> Result<i32> {
            Ok(42)
        }
        
        let result = test_function();
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 42);
    }
    
    #[test]
    fn test_error_chain() {
        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found");
        let our_err: Error = io_err.into();
        assert!(matches!(our_err, Error::Io(_)));
    }
}